package com.secxiot.common.utils;

import cn.jiguang.common.ClientConfig;
import cn.jiguang.common.ServiceHelper;
import cn.jiguang.common.connection.NettyHttpClient;
import cn.jiguang.common.resp.APIConnectionException;
import cn.jiguang.common.resp.APIRequestException;
import cn.jiguang.common.resp.BaseResult;
import cn.jiguang.common.resp.ResponseWrapper;
import cn.jpush.api.JPushClient;
import cn.jpush.api.push.CIDResult;
import cn.jpush.api.push.PushResult;
import cn.jpush.api.push.model.*;
import cn.jpush.api.push.model.audience.Audience;
import cn.jpush.api.push.model.audience.AudienceTarget;
import cn.jpush.api.push.model.notification.AndroidNotification;
import cn.jpush.api.push.model.notification.IosNotification;
import cn.jpush.api.push.model.notification.Notification;
import com.google.gson.Gson;
import io.netty.handler.codec.http.HttpMethod;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Component;
import org.springframework.util.CollectionUtils;

import java.net.URI;
import java.net.URISyntaxException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.ConcurrentLinkedDeque;

/**
 * Description: 极光推送
 * date:
 *
 * @author 谢磊
 * @since JDK 1.8
 */
@Component
public class JPushUtil {
    protected static final Logger LOG = LoggerFactory.getLogger(JPushUtil.class);

    // demo App defined in resources/jpush-api.conf
    protected static String APP_KEY = "b1cc1df33bd8c757c2935d21";
    protected static String MASTER_SECRET = "ac87e8dd25bf9584a1c2dd5d";

    @Value("${jpush.app_key}")
    public void setAppKey(String appKey) {
        APP_KEY = appKey;
    }

    @Value("${jpush.master_secret}")
    public void setMasterSecret(String master_secret) {
        MASTER_SECRET = master_secret;
    }

    private static ConcurrentHashMap<String, ConcurrentLinkedDeque<String>> CIDS = new ConcurrentHashMap<>();

    /**
     * 使用 NettyHttpClient 异步接口发送请求
     *
     * @param title 标题
     * @param alert 内容
     * @param alias 接收者别名
     */
    public static void sendPushWithCallback(String title, String alert, String... alias) {
        ClientConfig clientConfig = ClientConfig.getInstance();
        String host = (String) clientConfig.get(ClientConfig.PUSH_HOST_NAME);
        final NettyHttpClient client = new NettyHttpClient(ServiceHelper.getBasicAuthorization(APP_KEY, MASTER_SECRET),
                null, clientConfig);
        try {
            URI uri = new URI(host + clientConfig.get(ClientConfig.PUSH_PATH));
            PushPayload payload = buildPushObject_all_alias_alert(alert, alias);
            client.sendRequest(HttpMethod.POST, payload.toString(), uri, new NettyHttpClient.BaseCallback() {
                @Override
                public void onSucceed(ResponseWrapper responseWrapper) {
                    LOG.info("Got result: " + responseWrapper.responseContent);
                }
            });
        } catch (URISyntaxException e) {
            LOG.error("异步推送失败", e);
        }
    }

    /**
     * 单内容推送
     *
     * @param title  标题
     * @param alert  内容
     * @param alias  接收者别名
     * @param extras key-value 扩展字段
     * @return HTTP响应状态
     */
    public static JsendLog sendPush(String title, String alert, Map<String, String> extras, String... alias) {
        ClientConfig clientConfig = ClientConfig.getInstance();
        final JPushClient jpushClient = new JPushClient(MASTER_SECRET, APP_KEY, null, clientConfig);
        final PushPayload payload = buildPushObject_android_and_ios(title, alert, extras, alias);
        PushResult result;
        try {
            result = jpushClient.sendPush(payload);
            LOG.error("**********************************************推送任务返回开始***********************************************");
            int code = result.getResponseCode();
            LOG.info("Got result - " + result);
            LOG.info("**********************************************code - " + code);
            LOG.error("**********************************************推送任务返回结束****111111*******************************************");
            return new JsendLog(payload, result);
            // 如果使用 NettyHttpClient，需要手动调用 close 方法退出进程
            // If uses NettyHttpClient, call close when finished sending request, otherwise process will not exit.
            // jpushClient.close();
        } catch (APIConnectionException e) {
            LOG.error("Connection error. Should retry later. ", e);
            LOG.error("Sendno: " + payload.getSendno());
            LOG.error("**********************************************推送任务返回结束****222222*******************************************");
            return new JsendLog(payload, new PushResult());
        } catch (APIRequestException e) {
            LOG.error("Error response from JPush server. Should review and fix it. ", e);
            LOG.info("HTTP Status: " + e.getStatus());
            LOG.info("Error Code: " + e.getErrorCode());
            LOG.info("Error Message: " + e.getErrorMessage());
            LOG.info("Msg ID: " + e.getMsgId());
            LOG.error("Sendno: " + payload.getSendno());
            LOG.error("**********************************************推送任务返回结束****333333*******************************************");
            return new JsendLog(payload, new PushResult());
        }
    }

    /**
     * 加密单内容推送
     *
     * @param title  标题
     * @param alert  内容
     * @param alias  接收者别名
     * @param extras key-value 扩展字段
     * @return HTTP响应状态
     */
    public static PushResult sendPushWithEncrypt(String title, String alert, Map<String, String> extras, String... alias) {
        ClientConfig clientConfig = ClientConfig.getInstance();
        clientConfig.setEncryptType(EncryptKeys.ENCRYPT_SMS2_TYPE);
        final JPushClient jpushClient = new JPushClient(MASTER_SECRET, APP_KEY, null, clientConfig);
//        String authCode = ServiceHelper.getBasicAuthorization(APP_KEY, MASTER_SECRET);
        // Here you can use NativeHttpClient or NettyHttpClient or ApacheHttpClient.
        // Call setHttpClient to set httpClient,
        // If you don't invoke this method, default httpClient will use NativeHttpClient.

//        ApacheHttpClient httpClient = new ApacheHttpClient(authCode, null, clientConfig);
//        NettyHttpClient httpClient =new NettyHttpClient(authCode, null, clientConfig);
//        jpushClient.getPushClient().setHttpClient(httpClient);
        final PushPayload payload = buildPushObject_android_and_ios(title, alert, extras, alias);
//        // For push, all you need do is to build PushPayload object.
//        PushPayload payload = buildPushObject_all_alias_alert();
        try {
            PushResult result = jpushClient.sendPush(payload);
            LOG.info("Got result - " + result);
            System.out.println(result);
            return result;
            // 如果使用 NettyHttpClient，需要手动调用 close 方法退出进程
            // If uses NettyHttpClient, call close when finished sending request, otherwise process will not exit.
            // jpushClient.close();
        } catch (APIConnectionException e) {
            LOG.error("Connection error. Should retry later. ", e);
            LOG.error("Sendno: " + payload.getSendno());
            return new PushResult();
        } catch (APIRequestException e) {
            LOG.error("Error response from JPush server. Should review and fix it. ", e);
            LOG.info("HTTP Status: " + e.getStatus());
            LOG.info("Error Code: " + e.getErrorCode());
            LOG.info("Error Message: " + e.getErrorMessage());
            LOG.info("Msg ID: " + e.getMsgId());
            LOG.error("Sendno: " + payload.getSendno());
            return new PushResult();
        }
    }

    /**
     * 批量单推接口
     * https://docs.jiguang.cn/jpush/server/push/rest_api_v3_push/#vip
     */
    public static BatchPushResult batchSend(List<PushPayload> pushPayloadList) {

        JPushClient jPushClient = new JPushClient(MASTER_SECRET, APP_KEY);
        try {
            BatchPushResult result = jPushClient.batchSendPushByAlias(pushPayloadList);
            LOG.info("batchSendPushByAlias param: {}, result: {}", pushPayloadList, new Gson().toJson(result.getBatchPushResult()));
            return result;
        } catch (APIConnectionException e) {
            LOG.error("Connection error. Should retry later. ", e);
            return new BatchPushResult();
        } catch (APIRequestException e) {
            LOG.error("Error response from JPush server. Should review and fix it. ", e);
            LOG.info("HTTP Status: " + e.getStatus());
            LOG.info("Error Code: " + e.getErrorCode());
            LOG.info("Error Message: " + e.getErrorMessage());
            return new BatchPushResult();
        }
    }

    public static PushPayload buildPushObject_all_all_alert(String alert) {
        return PushPayload.alertAll(alert);
    }

    public static PushPayload buildPushObject_all_alias_alert(String alert, String... alias) {
        return PushPayload.newBuilder()
                .setPlatform(Platform.all())
                .setAudience(Audience.alias(alias))
                .setNotification(Notification.alert(alert))
                .build();
    }

    public static PushPayload buildPushObject_android_tag_alertWithTitle(String alert, String title, String... tags) {
        return PushPayload.newBuilder()
                .setPlatform(Platform.android())
                .setAudience(Audience.tag(tags))
                .setNotification(Notification.android(alert, title, null))
                .build();
    }

    public static PushPayload buildPushObject_android_and_ios(String title, String alert, Map<String, String> extras, String... alias) {
        IosNotification.Builder iosBuilder = IosNotification.newBuilder().incrBadge(1);
        if (!CollectionUtils.isEmpty(extras)) {
            for (String key : extras.keySet()) {
                iosBuilder.addExtra(key, extras.get(key));
            }
        }
        if (alias == null && alias.length < 1) {
            throw new RuntimeException("接收者空");
        }
        return PushPayload.newBuilder()
                .setPlatform(Platform.android_ios())
                .setAudience(Audience.newBuilder()
                        .addAudienceTarget(AudienceTarget.alias(alias))
                        .build())
                .setNotification(Notification.newBuilder()
                        .setAlert(alert)
                        .addPlatformNotification(AndroidNotification.newBuilder()
                                .setTitle(title)
                                .addExtras(extras).build())
                        .addPlatformNotification(iosBuilder.build())
                        .build())
                .build();
    }

    public static String getCidList(String type) {
        ConcurrentLinkedDeque<String> typeQue = CIDS.get(type);
        if (typeQue == null) {
            typeQue = new ConcurrentLinkedDeque<>();
            CIDS.put(type, typeQue);
        }

        if (typeQue.size() > 0) {
            return typeQue.peekLast();
        } else {
            JPushClient jPushClient = new JPushClient(MASTER_SECRET, APP_KEY);
            try {
                CIDResult result = jPushClient.getCidList(100, type);
                LOG.info("Got result - " + result);
                typeQue.addAll(result.cidlist);
                return typeQue.peekLast();
            } catch (APIConnectionException e) {
                LOG.error("Connection error. Should retry later. ", e);
                return null;
            } catch (APIRequestException e) {
                LOG.error("Error response from JP ush server. Should review and fix it. ", e);
                LOG.info("HTTP Status: " + e.getStatus());
                LOG.info("Error Code: " + e.getErrorCode());
                LOG.info("Error Message: " + e.getErrorMessage());
                return null;
            }
        }
    }

    public static class JsendLog {
        public PushPayload payload;

        public BaseResult result;

        public JsendLog(PushPayload payload, BaseResult result) {
            this.payload = payload;
            this.result = result;
        }
    }

    public static void main(String[] args) {
        List<String> sc = new ArrayList<String>();
        sc.add("102975821381633");
        String[] resArray = sc.toArray(new String[]{});
        Map<String, String> extras = new HashMap<>();
        //JsendLog jsendLog = JPushUtil.sendPush("06", "06", extras, resArray);
        JPushUtil.JsendLog jsendLog = JPushUtil.sendPush("新任务提醒", "一个新的任务", extras, resArray);
        PushResult result = (PushResult) jsendLog.result;
        System.out.println("-------------------------------------");
        LOG.error(result.toString());
    }

}
